/*
 * DeMarshall.h
 *
 *  Created on: 06-11-2008
 *      Author: christian
 */
#ifndef MARSHAL_H_
#define MARSHAL_H_
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include "Variant.h"
#include "XanguliException.h"

namespace Xanguli {

template <typename T>
struct type_traits;

template <class T>
struct type_traits< std::vector<T> >{
	static int const value = DBUS_TYPE_ARRAY;
};

template <typename K, typename V>
struct type_traits< std::map<K,V> >{

};

template <>
struct type_traits<int> {
	static int const value = DBUS_TYPE_INT32;
};

template <>
struct type_traits<unsigned int> {
	static int const value = DBUS_TYPE_UINT32;
};

template <>
struct type_traits<std::string> {
	static int const value = DBUS_TYPE_STRING;
};


/*
template <typename K, typename V> int dbus_type(std::map<K,V>& m) {
	return DBUS_TYPE_ARRAY;
}

int dbus_type(unsigned int& ui);
int dbus_type(int& i);
int dbus_type(Variant& v);
int dbus_type(std::string& s);
*/

template <typename T> void serialize(DBusMessageIter* iter, T& elem) {
	dbus_message_iter_append(iter, dbus_type(elem), &elem);
}

void serialize(DBusMessageIter* iter, std::string s);
void serialize(DBusMessageIter* iter, Variant v);

template<typename T> void serialize(DBusMessageIter* iter, std::vector<T> v) {
	DBusMessageIter sub;
	const char contained_signature = dbus_type(v);
	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, &contained_signature, &sub);
	typename std::vector<T>::iterator vec_iter;
	for (vec_iter = v.begin(); vec_iter != v.end(); vec_iter++) {
		serialize(&sub, vec_iter());
	}
	dbus_message_iter_close_container(iter, &sub);
}

template<typename K, typename V> void serialize(DBusMessageIter* iter, std::map<K,V> m) {
	DBusMessageIter sub;
	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "e", &sub);
	typename std::map<K,V>::iterator map_iterator;
    for(map_iterator = m.begin(); map_iterator != m.end(); map_iterator++) {
    	DBusMessageIter subsub;
    	dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &subsub);
    	serialize(&subsub, map_iterator->first);
    	serialize(&subsub, map_iterator->second);
    	dbus_message_iter_close_container(&sub, &subsub);
    }
    dbus_message_iter_close_container(iter, &sub);
}

void deserialize(DBusMessageIter* iter, unsigned int& ui);
void deserialize(DBusMessageIter* iter, int& i);
void deserialize(DBusMessageIter* iter, std::string& s);
void deserialize(DBusMessageIter* iter, Variant& v);

template<class T> void deserialize(DBusMessageIter* iter, std::vector<T>& v) {
	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
		throw new XanguliException("Expected array");
	}
	DBusMessageIter sub;
	dbus_message_iter_recurse(iter, &sub);
	while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
		T element;
		deserialize(&sub, element);
		v.push_back(element);
	}
	dbus_message_iter_next(iter);
}

template<typename K, typename V> void deserialize(DBusMessageIter* iter, std::map<K,V>& m) {
	std::cout << "Deserialize map\n";
	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
		throw new XanguliException("Expected array\n");
	}
	DBusMessageIter sub;
	dbus_message_iter_recurse(iter, &sub);
	int type;
	while ((type = dbus_message_iter_get_arg_type(&sub)) != DBUS_TYPE_INVALID) {
		std::cout << "Looping\n";
		if (type != DBUS_TYPE_DICT_ENTRY) {
			throw new XanguliException("Expected dict entry\n");
		}
		DBusMessageIter subsub;
		dbus_message_iter_recurse(&sub, &subsub);
		K key;
		std::cout << "deserialize key\n";
		deserialize(&subsub, key);
		V val;
		std::cout << "deserialize value\n";
		deserialize(&subsub, val);
		std::cout << "(" << key << ", " << val.asString() << ")\n";
		m[key] = val;
		//<< ", " << value << "\n";
		dbus_message_iter_next(&sub);
	}
	dbus_message_iter_next(iter);
}

}
#endif /* MARSHAL_H_ */
